package really.simple.file.manager;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.ResourceBundle;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

public class ReallySimpleFileManagerActivity extends ListActivity {
	
	private List<String> item = null;
	private List<String> path = null;
	private String root="/";
	private TextView myPath;
	
	private String currentDir;
	private File[] files;
	
	private String pathCut = "";
	private String pathCopy = "";
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        myPath = (TextView)findViewById(R.id.path);
        getDir(root);
    }
    
    private void getDir(String dirPath)
    {
    	currentDir = dirPath;
    	myPath.setText("Location: " + dirPath);
    	
    	item = new ArrayList<String>();
    	path = new ArrayList<String>();
    	
    	File f = new File(dirPath);
    	files = f.listFiles();
    	
    	if(!dirPath.equals(root))
    	{

    		item.add(root);
    		path.add(root);
    		
    		item.add("../");
    		path.add(f.getParent());
            
    	}
    	
    	for(int i=0; i < files.length; i++)
    	{
    			File file = files[i];
    			path.add(file.getPath());
    			if(file.isDirectory())
    				item.add(file.getName() + "/");
    			else
    				item.add(file.getName());
    	}

    	ArrayAdapter<String> fileList =
    		new ArrayAdapter<String>(this, R.layout.row, item);
    	setListAdapter(fileList);
        registerForContextMenu(this.getListView());
    }

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		
		File file = new File(path.get(position));
		
		if (file.isDirectory())
		{
			if(file.canRead())
			{
				getDir(file.getPath());
			}
			else
			{
				message("[" + file.getName() + "] folder can't be read!");
			}
		}
		else if (file.isFile()) {
			try {
	            AlertDialog.Builder alert = new AlertDialog.Builder(this);
	    		alert.setTitle(file.getPath());
	
	
				FileReader buff = new FileReader(file);
				BufferedReader reader = new BufferedReader(buff);
				String line;
				StringBuilder text = new StringBuilder();
				text.append("");
				while ((line = reader.readLine()) != "" && line != null) {
					text.append(line);
					text.append("\n");
				}
				
	    		alert.setMessage(text);
	    		alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
	    		public void onClick(DialogInterface dialog, int whichButton) {
	    		}});
	
	    		alert.show();
			}
			catch (IOException e) {
				message("Cannot read this file!");
			}
		}
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
	    MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.layout.menu, menu);
	    return true;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
        //Disable some menu item
        if (pathCut == "" && pathCopy == "")
        	menu.findItem(R.id.paste).setEnabled(false);
        else
        	menu.findItem(R.id.paste).setEnabled(true);
        return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    // Handle item selection
	    switch (item.getItemId()) {
	    case R.id.new_folder:
	        newFolder();
	        return true;
	    case R.id.new_file:
	        newFile();
	        return true;
	    case R.id.paste:
	        paste();
	        return true;
	    default:
	        return super.onOptionsItemSelected(item);
	    }
	}
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
    		ContextMenuInfo menuInfo) {
    	if (v.getId()==getListView().getId()) {
    	    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
    		if (item.get(info.position) == root || item.get(info.position) == "../") {
    			return;//do not create context menu for / and ../
    		}
    		menu.setHeaderTitle(item.get(info.position));
    		
    		MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.layout.context_menu, menu);
            
            //Disable some menu item
            int pos;
            if (currentDir.equals(root)) {
            	pos = info.position;
            }
            else {
            	pos = info.position - 2;
            }
        	if (files[pos].isDirectory())
        		menu.findItem(R.id.edit).setEnabled(false);
    	}
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem menuitem) {
	    /*AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuitem.getMenuInfo();
	    int menuItemIndex = menuitem.getItemId();
		String[] menuItems = getResources().getStringArray(R.array.contextmenu);
		String menuItemName = menuItems[menuItemIndex];
	    String listItemName = item.get(info.position);
	    
	    TextView text = (TextView)findViewById(R.id.footer);
	    text.setText(String.format("Selected %s for item %s", menuItemName, listItemName));
    	return true;*/

    	AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuitem.getMenuInfo();
	    switch (menuitem.getItemId()) {
	    case R.id.cut:
	        cut(info.position);
	        return true;
	    case R.id.copy:
	        copy(info.position);
	        return true;
	    case R.id.edit:
	        edit(info.position);
	        return true;
	    case R.id.delete:
	        delete(info.position);
	        return true;
	    case R.id.rename:
	        rename(info.position);
	        return true;
	    case R.id.properties:
	        properties(info.position);
	        return true;
	    default:
	        return super.onContextItemSelected(menuitem);
	    }
    }
	
	private void properties(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		File file = new File(filepath);

        String properties = getFileProperties(file);
		message(properties);
	}

	private String getFileProperties(File file) {
		// TODO Auto-generated method stub
		String properties = "";
		properties += "Name: " + file.getName() + "\n";
		properties += "Path: " + file.getPath() + "\n";
		properties += "Can Execute: " + file.canExecute() + "\n";
		properties += "Can Read: " + file.canRead() + "\n";
		properties += "Can Write: " + file.canWrite() + "\n";
		properties += "Type: " + (file.isDirectory()?"Directory":"File") + "\n";
		properties += "Is Hidden: " + file.isHidden() + "\n";
		return properties;
	}

	private void rename(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		final File file = new File(filepath);

		if (file.canWrite()) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this);
	
			alert.setTitle("New Name");
	
			final EditText input = new EditText(this);
			input.setSingleLine(true);
			alert.setView(input);
	
			alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
			  String name = input.getText().toString();
			  // Do something with value!
			  file.renameTo(new File(currentDir + "/" + name));
			  //refresh
			  getDir(currentDir);
			}});
	
			alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			  public void onClick(DialogInterface dialog, int whichButton) {
			    // Canceled.
			  }
			});
	
			alert.show();
		}
		else {
			message("Cannot rename this file (folder)!");
		}
	}

	private void delete(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		
		File file = new File(filepath);
		if (file.isDirectory()) {
			deleteDirectory(file);
		}
		else {
			deleteFile(file);
		}
		//refresh
		getDir(currentDir);
	}

	  private boolean deleteFile(File file) {
		// TODO Auto-generated method stub
	  	if (file.canWrite()) {
	  		boolean deleted = file.delete();
	  		return deleted;
		}
		else {
			message("Can not delete this file!");
		}
	  	return false;
	}

	public boolean deleteDirectory(File path) {
	  	if (path.canWrite()) {
		    if( path.exists() ) {
		      File[] files = path.listFiles();
		      for(int i=0; i<files.length; i++) {
		         if(files[i].isDirectory()) {
		           deleteDirectory(files[i]);
		         }
		         else {
		           files[i].delete();
		         }
		      }
		    }
		    return( path.delete() );
		}
		else {
			message("Can not delete this folder!");
		}
	  	return false;
	  }

	private void edit(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		final File file = new File(filepath);
		
		if (file.canWrite() && file.isFile() && isTextFile(file)) {
			try {
				FileReader buff = new FileReader(file);
				BufferedReader reader = new BufferedReader(buff);
				String line;
				StringBuilder text = new StringBuilder();
				text.append("");
				while ((line = reader.readLine()) != "" && line != null) {
					text.append(line);
					text.append("\n");
				}
	            AlertDialog.Builder alert = new AlertDialog.Builder(this);
	    		alert.setTitle("Edit File");

	    		// Set an EditText view to get user input 
	    		final EditText input = new EditText(this);
	    		input.setHeight(200);
	    		input.setText(text);
	    		alert.setView(input);

	    		alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
	    		public void onClick(DialogInterface dialog, int whichButton) {
	    			try {
		    			String editedText = input.getText().toString();
		    			// Do something with value!
		    			BufferedWriter writer = new BufferedWriter(new FileWriter(file, false));
		    	        writer.write(editedText);
		    	        writer.flush();
		    	        writer.close();
	    			}
	    			catch (IOException e) {
	    				message("Cannot save file!");
	    			}
	    		}});

	    		alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
	    		  public void onClick(DialogInterface dialog, int whichButton) {
	    		    // Canceled.
	    		  }
	    		});

	    		alert.show();
			}
			catch(IOException e) {
				message("Cannot edit this file!");
			}
		}
		else {
			message("You need to choose a text file with write permission");
		}
	}

	private boolean isTextFile(File file) {
		// TODO Auto-generated method stub
		 boolean match = file.getName().matches("([^\\s]+(\\.(?i)(txt))$)");
		 return match;
	}

	private String getBase(File file) {
		// TODO Auto-generated method stub
		String[] tokens = file.getName().split("\\.(?=[^\\.]+$)");
		return tokens[0];
	}

	private String getExtension(File file) {
		// TODO Auto-generated method stub
		String[] tokens = file.getName().split("\\.(?=[^\\.]+$)");
		return tokens[1];
	}

	private void copy(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		File file = new File(filepath);
		if (file.canRead()) {
			pathCut = "";
			pathCopy = filepath;
			invalidateOptionsMenu();
		}
		else {
			message("Cannot copy this file (folder)!");
		}
	}

	private void cut(int index) {
		// TODO Auto-generated method stub
		String filepath = currentDir + "/" + item.get(index);
		File file = new File(filepath);
		if (file.canWrite()) {
			pathCut = filepath;
			pathCopy = "";
			invalidateOptionsMenu();
		}
		else {
			message("Cannot move this file (folder)!");
		}
	}

	public boolean createDirIfNotExists(String path) {
		File file = new File(currentDir + "/" + path);
		if (!file.exists() && file.mkdirs()){
			//refresh
			getDir(currentDir);
		}
		else {
		  Log.e("Unable to create ", file.getPath());
		  message("Unable to create " + file.getPath());
		}
		return true;
	}

	private void createFileIfNotExists(String name) {
		// TODO Auto-generated method stub

		File file = new File(currentDir + "/" + name);
		try {
			if (!file.exists() && file.createNewFile()){
				//refresh
				getDir(currentDir);
			}
			else {
			  message("Unable to create " + file.getPath());
			}
		}
		catch(IOException e) {
			  message("Unable to create " + file.getPath());
		}
	}
	
	private void message(String message) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(message)
				.setNegativeButton("Ok", new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						dialog.cancel();
					}
				});
		AlertDialog alert = builder.create();
		alert.show();
	}

	private void paste() {
		// TODO Auto-generated method stub
		if (pathCut == "" && pathCopy != "") {
			File src = new File(pathCopy);
			String srcParentDir = src.getParent();
			String dstFileName;
			File dst;
			if (src.isFile()) 
			{
				dstFileName  = currentDir + "/" + ((srcParentDir.equals(currentDir))?getBase(src).concat("_copy"):getBase(src)) + "." + getExtension(src);
				dst  = new File(dstFileName);
				try {
					copyFile(src, dst);
			        getDir(currentDir);
				}
				catch (IOException e) {
					message("Cannot copy file to here!");
				}
			}
			else if (src.isDirectory()) {
				dstFileName  = currentDir + "/" + ((srcParentDir.equals(currentDir))?src.getName().concat("_copy"):src.getName());
				dst  = new File(dstFileName);
	            try {
		         	copyFolder(src,dst);
			        getDir(currentDir);
	            } catch(IOException e){
					message("Cannot copy folder to here!");
	            }
			}
		}
		else if (pathCut != "" && pathCopy == "") {
			File src = new File(pathCut);
			String srcParentDir = src.getParent();
			String dstFileName;
			File dst;
			if (src.isFile()) {
				if (srcParentDir.equals(currentDir)) {
					message("Cannot move this file to the same directory!");
					return;
				}
				dstFileName  = currentDir + "/" + src.getName();
				dst  = new File(dstFileName);
				try {
					copyFile(src, dst);
			        src.delete();
			        getDir(currentDir);
				}
				catch (IOException e) {
					message("Cannot move file to here!");
				}
			}
			else if (src.isDirectory()) {
				if (srcParentDir.equals(currentDir)) {
					message("Cannot move this folder to the same directory!");
					return;
				}
				dstFileName  = currentDir + "/" + src.getName();
				dst  = new File(dstFileName);
	            try {
		         	copyFolder(src,dst);
		         	deleteDirectory(src);
			        getDir(currentDir);
	            } catch(IOException e){
					message("Cannot copy folder to here!");
	            }
			}
		}
	}
	
	private void copyFolder(File src, File dst) throws IOException{
		// TODO Auto-generated method stub
		if(src.isDirectory()) {
    		//if directory not exists, create it
    		if(!dst.exists()){
    		   dst.mkdir();
    		}
 
    		//list all the directory contents
    		String files[] = src.list();
 
    		for (String file : files) {
    		   //construct the src and dest file structure
    		   File srcFile = new File(src, file);
    		   File destFile = new File(dst, file);
    		   //recursive copy
    		   copyFolder(srcFile,destFile);
    		}
    	} else {
    		copyFile(src, dst);
    	}
	}

	private void copyFile(File src, File dst) throws IOException {
		    FileChannel inChannel = new FileInputStream(src).getChannel();
		    FileChannel outChannel = new FileOutputStream(dst).getChannel();
		    try
		    {
		        inChannel.transferTo(0, inChannel.size(), outChannel);
		    }
		    finally
		    {
		        if (inChannel != null)
		            inChannel.close();
		        if (outChannel != null)
		            outChannel.close();
		    }
	}

	private void newFile() {
		// TODO Auto-generated method stub
		File current = new File(currentDir);
		if (current.canWrite()) {
			AlertDialog.Builder alert = new AlertDialog.Builder(this);

			alert.setTitle("File Name");

			// Set an EditText view to get user input 
			final EditText input = new EditText(this);
			input.setSingleLine(true);
			alert.setView(input);

			alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
			  String name = input.getText().toString();
			  // Do something with value!
			  createFileIfNotExists(name);
			}});

			alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			  public void onClick(DialogInterface dialog, int whichButton) {
			    // Canceled.
			  }
			});

			alert.show();
		}
		else {
			message("Cannot create new file here!");
		}
	}

	private void newFolder() {
		// TODO Auto-generated method stub
		AlertDialog.Builder alert = new AlertDialog.Builder(this);

		alert.setTitle("Folder Name");

		// Set an EditText view to get user input 
		final EditText input = new EditText(this);
		input.setSingleLine(true);
		alert.setView(input);

		alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
		public void onClick(DialogInterface dialog, int whichButton) {
		  String name = input.getText().toString();
		  // Do something with value!
		  createDirIfNotExists(name);
		}});

		alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
		  public void onClick(DialogInterface dialog, int whichButton) {
		    // Canceled.
		  }
		});

		alert.show();
		
	}
}